from epics import caput, caget, poll
import time
from beam_logging import getLogger
import re
from json import loads
from pcaspy import Driver, SimpleServer


def read_data(config_name: str = None):
    try:
        with open("./config/{}.json".format(config_name), "r", encoding="utf-8") as fp:
            context = fp.read()
            dict_data = loads(context)
            fp.close()
        if config_name == None:
            return True, dict_data
        else:
            try:
                result = dict_data["PV"]
                return True, result
            except KeyError as e:
                return False, "无此配置项"

    except IOError as e:
        return False, "读取配置文件错误"


class myDriver(Driver):
    def __init__(self):
        super(myDriver, self).__init__()


def pv_publish(load_mode_list):
    logger = getLogger("IOC")
    logger.debug("IOC 正在运行")
    prefix = ''
    pvdb = {}
    for config_name in load_mode_list:
        file_flag, PV_data = read_data(config_name)
        if file_flag:
            for Rule in PV_data["Rule"]:
                if "bypass" in Rule.keys():
                    pvdb[Rule["bypass"]] = {
                        'type': 'int',
                        'value': 0
                    }
                if "limit" in Rule.keys():
                    if isinstance(Rule["limit"],dict):
                        for pvname,value in Rule["limit"].items():
                            pvdb[pvname] = {
                                'type': 'float',
                                'value': value
                            }
                    else:
                        pvdb[Rule["limit"]] = {
                                'type': 'float',
                                'value': 0
                            }
                pvdb[Rule["status"]] = {
                    'type': 'int',
                    'value': 0
                }
            pvdb[PV_data["T_Status"]] = {
                'type': 'int',
                'value': 0
            }
    server = SimpleServer()
    server.createPV(prefix, pvdb)
    driver = myDriver()
    for pv in driver.pvDB.keys():
        logger.info("{:<50}\t已发布".format(pv))
    while True:
        # process CA transactions
        server.process(0.5)


def Calc_pv(data: dict):
    calc_str = data["calc"]
    for i in range(len(data["pv"])):
        calc_str = re.sub("pv{}.get".format(
            i), str(caget(data["pv"][i])), calc_str)
        calc_str = re.sub("pv{}.put\(".format(i),"caput(\"{}\",".format(data["pv"][i]), calc_str)
    if not "bypass" in data.keys() or "bypass" in data.keys() and caget(data["bypass"]) == 0 and not caget(data["bypass"]) == None:
        try:
            result = eval(calc_str)
        except:
            print("计算错误:{}".format(calc_str))
            return 0
    elif caget(data["bypass"]) == 1:
        result = 2
    else:
        result = -1
    if "status" in data.keys():
        caput(data["status"], result)
    return result


def Config_Apply(config_name):
    logger = getLogger(config_name)
    file_flag, PV_data = read_data(config_name)
    # print(PV_data)
    if not file_flag:
        logger.debug("请检查{}配置".format(config_name))
    else:
        logger.debug("{} 正在运行".format(config_name))
        last_index = -1
        last_count = 0
        while (True):
            poll()
            time.sleep(0.1)
            result_list = []
            for data in PV_data["Rule"]:
                result_list.append(Calc_pv(data))
            if 0 in result_list:
                index = result_list.index(0)
                count = result_list.count(0)
                if not index == last_index and not count == last_count:
                    last_index = index
                    last_count = count

                    while 0 in result_list:
                        logger.info(PV_data["Rule"]
                                    [result_list.index(0)])
                        result_list[result_list.index(0)] = -1

                caput(PV_data["T_Status"], 0)
                if isinstance(PV_data["T_OUT"],dict):
                    Calc_pv(PV_data["T_OUT"])
                else:
                    caput(PV_data["T_OUT"], 0)
            else:
                caput(PV_data["T_Status"], 1)
                #caput(PV_data["T_OUT"], 1)


if __name__ == '__main__':
    Config_Apply("LLRF")
